<template>
	<ScrollArea
		ref="scrollAreaRef"
		class="pf-Select_options"
		:style="optionsStyle()"
		@container-resize="containerResize"
		@scroll-resize="scrollResize"
		@scroll="scrollFn"
	>
		<VirtualScroll
			v-if="showOptions.length"
			ref="virtualScrollRef"
			v-slot="{index,item}"
			:data="showOptions"
			direction="y"
			:min-size="virtualMinSize"
			:preload="virtualPreload"
			:scroll-offset="scrollOffset"
			:view-size="viewSize"
			class="pf-Select_content"
			:style="contentStyle()"
		>
			<slot
				name="option"
				:index="index"
				:item="item"
				:selected-data="selectedData"
				:select-fn="selectFn"
			>
				<div
					:key="item.value"
					:class="optionItemClasses(item)"
					@click="selectFn(item)"
				>{{item.label}}</div>
			</slot>
		</VirtualScroll>
		<div
			v-else-if="options.length"
			class="pf-Select_nodata"
			:style="{minWidth:minWidth+'px'}"
		>
			<slot
				name="nomatch"
				v-bind="slotScope()"
			>
				<div
					class="pf-Select_nodataText"
					:style="{width:minWidth+'px'}"
				>{{nomatchText||lang.Select.nomatch}}</div>
			</slot>
		</div>
		<div
			v-else
			class="pf-Select_nodata"
			:style="{minWidth:minWidth+'px'}"
		>
			<slot
				name="nodata"
				v-bind="slotScope()"
			>
				<div
					class="pf-Select_nodataText"
					:style="{width:minWidth+'px'}"
				>{{nodataText||lang.Select.nodata}}</div>
			</slot>
		</div>
	</ScrollArea>
</template>

<script setup lang="ts">
import type {
	SelectSelectedData,
} from './type';
import type {
	LimitProcessor,
} from '../Floating/type';
import {
	shallowRef,
	computed,
	nextTick,
} from 'vue';
import ScrollArea from '../ScrollArea/ScrollArea.vue';
import VirtualScroll from '../VirtualScroll/VirtualScroll.vue';
import {lang} from '../../../locale';
if(typeof cache==='function'){
	cache=cache();
}
const {defaultFilterMethod}=cache;

const emit=defineEmits<{
	(e:'click',opt:SelectStandardOption):void;
}>();
const props=withDefaults(defineProps<{
	selectedData:SelectSelectedData;
	options:Array<SelectStandardOption>;
	filterText?:string;
	filterMethod?:(text:string,opt:SelectStandardOption) => boolean;
	nodataText?:string;
	nomatchText?:string;
	virtualMinSize?:number;
	virtualPreload?:number;
	maxHeight?:number;
	padding?:number;
	minWidth:number;
	computePoptip:(limitFn?:LimitProcessor) => Promise<boolean>;
}>(),{
	virtualMinSize:30,
	maxHeight:250,
	padding:5,
});
const scrollAreaRef=shallowRef();
const virtualScrollRef=shallowRef();
const scrollSize=shallowRef({
	width:0,
	height:0,
});
const viewSize=shallowRef(0);
const scrollOffset=shallowRef(0);
const enableLimit=shallowRef(true);
const limit=shallowRef([]);
//region 显示的选项
const showOptions=computed(() => {
	const {filterText,options}=props;
	if(!filterText){
		return options;
	}
	const filterMethod=props.filterMethod||defaultFilterMethod;
	return options.filter((option) => {
		return filterMethod(filterText,option);
	});
});
//endregion
//region 选项类名
const optionItemClasses=(option:SelectStandardOption) => {
	const {isSelected}=props.selectedData;
	return 'pf-Select_optionItem'+
		(option.disabled?' pf--disabled':'')+
		(isSelected(option)?' pf--active':'');
};
//endregion
//region 下拉菜单样式
const optionsStyle=() => {
	const {minWidth,maxHeight}=props;
	const [limitWidth,limitHeight]=limit.value;
	let {width,height}=scrollSize.value;
	if(enableLimit.value&&limitHeight&&height>limitHeight){
		height=limitHeight;
	}
	if(maxHeight&&height>maxHeight){
		height=maxHeight;
	}
	if(width<minWidth){
		width=minWidth;
	}
	if(limitWidth&&width>limitWidth){
		width=limitWidth;
	}
	return {
		height:height+'px',
		width:width+'px',
	};
};
//endregion
//region 下拉菜单内容样式
const contentStyle=() => {
	return {
		margin:props.padding+'px 0',
		minWidth:props.minWidth+'px',
	};
};
//endregion
//region 插槽作用域
const slotScope=() => {
	return {
		width:props.minWidth,
	};
};
//endregion
//region 滚动容器变化
function containerResize({height}){
	viewSize.value=height;
}
function scrollResize(size){
	scrollSize.value=size;
	enableLimit.value=false;
	nextTick(() => {
		props.computePoptip((limitWidth,limitHeight) => {
			enableLimit.value=true;
			limit.value=[limitWidth,limitHeight];
			return nextTick();
		}).then(() => {
			scrollToSelect();
		});
	});
}
function scrollFn({y}){
	scrollOffset.value=y;
}
//endregion
//region 选择事件
function selectFn(option:SelectStandardOption){
	emit('click',option);
}
//endregion
//region 滚动到选中选
function scrollToSelect(){
	const {selected}=props.selectedData;
	if(Array.isArray(selected)){
		return;
	}
	const index=showOptions.value.indexOf(selected);
	if(index>-1){
		const scrollArea=scrollAreaRef.value;
		let {offset,itemSize}=virtualScrollRef.value.getInfo(index,'start');
		offset+=props.padding;
		const {containerSize,position}=scrollArea.getInfo();
		const curScrollOffset=position.y;
		const viewSize=containerSize.height-props.padding;
		if(offset+itemSize>curScrollOffset+viewSize){
			scrollArea.setScrollPosition('y',offset-(viewSize-itemSize));
		}
	}
}
//endregion
</script>

<script lang="ts">
import type {
	SelectStandardOption,
} from './type';
//region 类型声明
interface Cache{
	// eslint-disable-next-line no-unused-vars
	defaultFilterMethod:(text:string,opt:SelectStandardOption) => boolean;
}
//endregion
//region 全局缓存
let cache:Cache|(() => Cache)=function(){
	return {
		defaultFilterMethod(text,{label}){
			return label.toLocaleLowerCase().indexOf(text)>-1;
		},
	};
};
//endregion
export default {};
</script>